
import logging
import sys

DEBUG = logging.DEBUG
INFO = logging.INFO
WARNING = logging.WARNING
ERROR = logging.ERROR
CRITICAL = logging.CRITICAL

FORMAT = "[%(loggername)s] %(ipaddress)s %(username)s %(group)s %(asctime)s \"%(request)s\" %(status)s %(errormessage)s"

def current_function(depth=0,includefile=True):
	try:
		co = sys._getframe(depth).f_back.f_code
		if includefile:
			filename = co.co_filename.rsplit('/',1)
			return ''.join((filename[1],':',co.co_name))
		else:
			return str(co.co_name)
	except:
		return '(unknown function)'
	
class IOLogger(object):

	def __init__(self):
		
		self.filelogging = None
		self.standardlogging = None
		self.streamlogging = None
				
	def log_access(self,ipaddress,username,group,request,status,errormessage):
		"""log_access(self,ipaddress,username,group,request,status,errormessage):"""
		msgparams = {'ipaddress':ipaddress,'username':username,'group':group,'request':request,'status':status,'errormessage':errormessage}
		
		if self.filelogging is not None: self.filelogging.log_access(msgparams)
		if self.standardlogging is not None: self.standardlogging.log_access(msgparams)
		if self.streamlogging is not None: self.streamlogging.log_access(msgparams)
		
		
	def log_error(self,loglevel,ipaddress,username,group,request,status,errormessage):
		"""log_error(self,loglevel,ipaddress,username,group,request,status,errormessage):"""
		msgparams = {'ipaddress':ipaddress,'username':username,'group':group,'request':request,'status':status,'errormessage':errormessage}
		
		if self.filelogging is not None: self.filelogging.log_error(loglevel,msgparams)
		if self.standardlogging is not None: self.standardlogging.log_error(loglevel,msgparams)
		if self.streamlogging is not None: self.streamlogging.log_error(loglevel,msgparams)

class IOBaseLogger(object):
	
	loggermappings = {'IOFileLogger':logging.FileHandler,'IOStdLogger':logging.StreamHandler}
	
	def __init__(self,logconfig=None):
		
		if logconfig is None:
			raise AttributeError('logconfig can not be None')
		
		self.LogLevel = logconfig.LogLevel.value
		self.Access = logconfig.Access.value
		self.Error = logconfig.Error.value
		self.Name = logconfig.Name.value
		
		self.accesslog = None
		self.errorlog = None
		
	def log_access(self,msgparams):
		if self.accesslog is not None:
			msgparams['loggername'] = self.Name
			self.accesslog.log(INFO,'',extra=msgparams)

	def log_error(self,level,msgparams):
		if self.errorlog is not None:
			msgparams['loggername'] = self.Name
			self.errorlog.log(level,'',extra=msgparams)

	def handle_update(self,env,path,iobject):
		
		if hasattr(self,iobject.name):
			currentsetting = self.__getattribute__(iobject.name)
			if currentsetting != iobject.value:
				self.__setattr__(iobject.name,iobject.value)	
	
class IOFileLogger(IOBaseLogger):
	
	def __init__(self,logconfig=None):
		
		IOBaseLogger.__init__(self,logconfig)
		
		if self.Access != 'None':
			self._accesslogger = logging.FileHandler(self.Access)	
			self._accesslogger.setLevel(self.LogLevel)
			self._accesslogger.setFormatter(logging.Formatter(FORMAT))
			self.accesslog = logging.getLogger(self.Name + '.IOFileLogger.access')
			self.accesslog.addHandler(self._accesslogger)
			self.accesslog.setLevel(self._accesslogger.level)
		
		if self.Error != 'None':
			self._errorlogger = logging.FileHandler(self.Error)
			self._errorlogger.setLevel(self.LogLevel)
			self._errorlogger.setFormatter(logging.Formatter(FORMAT))			
			self.errorlog = logging.getLogger(self.Name + '.IOFileLogger.error')		
			self.errorlog.addHandler(self._errorlogger)		
			self.errorlog.setLevel(self._errorlogger.level)

class IOStreamLogger(IOBaseLogger):
	
	def __init__(self):
		pass

class IOStdLogger(IOBaseLogger):
	
	def __init__(self,logconfig=None):
		
		IOBaseLogger.__init__(self,logconfig)

		self._accesslogger = logging.StreamHandler(sys.stdout)
		self._errorlogger = logging.StreamHandler(sys.stderr)
		
		self._accesslogger.setLevel(self.LogLevel)
		self._accesslogger.setFormatter(logging.Formatter(FORMAT))
		
		self._errorlogger.setLevel(self.LogLevel)
		self._errorlogger.setFormatter(logging.Formatter(FORMAT))
		
		self.accesslog = logging.getLogger(self.Name + '.IOStdLogger.access')
		self.errorlog = logging.getLogger(self.Name + '.IOStdLogger.error')
		
		self.accesslog.addHandler(self._accesslogger)
		self.errorlog.addHandler(self._errorlogger)
		
		self.accesslog.setLevel(self._accesslogger.level)
		self.errorlog.setLevel(self._errorlogger.level)

class IONullLogger:
		
	def __init__(self):
		pass
		
	def log_access(self,ipaddress,username,group,request,status,errormessage):
		pass
				
	def log_error(self,loglevel,ipaddress,username,group,request,status,errormessage):
		pass

import coffeetalk.protocol.iotypes
	
class IOLoggerSettings(coffeetalk.protocol.iotypes.defaulttype.DefaultType):

	LogLevel = coffeetalk.protocol.iotypes.Integer(name="LogLevel",value="10")
	Access = coffeetalk.protocol.iotypes.String(name="Access",value="None")
	Name = coffeetalk.protocol.iotypes.String(name="Name",value="Server")
	Error = coffeetalk.protocol.iotypes.String(name="Error",value="None")

	def __init__(self,name=None,**kwargs):
		if name is None:
			name = 'LoggerSettings'
		coffeetalk.protocol.iotypes.defaulttype.DefaultType.__init__(self,name=name,**kwargs)

EXAMPLE_IOML = """
<ioml version="1.0">
<h />
<b>
<i n="StandardLogging" type="coffeetalk.server.settings.Logging">
    <i n="LogLevel" type="[Integer]" value="0" />
    <i n="Access" type="[String]" value="None" />
    <i n="Name" type="[String]" value="Server" />
    <i n="Error" type="[String]" value="None" />
</i>
</b>
</ioml>
"""
if __name__ == '__main__':
	
	#from coffeetalk.server.settings import _logging
	logger = IOLogger()
	
	config = IOLoggerSettings(name='Logger')
	config.LogLevel.value = INFO
	#config.Access.value = 'None'
	config.Name.value = 'Mike\'s Cool Server'
	
	logger.standardlogging = IOStdLogger(config)
	
#	fileconfig = _logging.Logging(name='Logger')
#	fileconfig.Access.value = 'access.log'
#	fileconfig.Error.value = 'error.log'
#	fileconfig.LogLevel.value = DEBUG
#	
#	logger.filelogger = IOFileLogger(fileconfig)
	
	logger.log_access('0.0.0.0','Mike','Users','/Apps/','200','')
	logger.log_error(WARNING,'0.0.0.0','Mike','Users','/Apps/','401','Unauthorized')
	